﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Shapes;
using System.Xml;
using Application = System.Windows.Forms.Application;
//#JMJ Create_20241130

namespace IHateWorking.Model
{
    public class FilePath
    {
        public FilePath()
        {
            DirectoryInfo dir = new DirectoryInfo(Application.StartupPath);

            DirectoryInfo rootDir = dir.Parent.Parent;
            Root = rootDir.FullName;

            ConfigPath = Root + @"\Config.xml";
            ResourceDir = CreateFilePath(Root + @"\Resources");
            MusicListPath = Root + @"\Resources\小金的歌单.xlsx";
            InformationsDir = CreateFilePath(Root + @"\Resources\Informations");
            LyricsDir = CreateFilePath(Root + @"\Resources\Lyrics");
            ScoresDir = CreateFilePath(Root + @"\Resources\Scores");
        }
        #region //////////////////////////////静态变量//////////////////////////////
        /// <summary>
        /// 静态接口
        /// </summary>
        public static FilePath Instance { get; set; } = new FilePath();

        #endregion 以上：/////////////////////静态变量//////////////////////////////

        #region //////////////////////////////非静态变量////////////////////////////
        /// <summary>
        /// 根目录地址
        /// </summary>
        public string Root { get; set; }
        
        /// <summary>
        /// 配置文件
        /// </summary>
        public string ConfigPath { get; set; }

        /// <summary>
        /// 资源文件夹
        /// </summary>
        public string ResourceDir { get; set; }

        /// <summary>
        /// 创作者文件夹
        /// </summary>
        public string CreatorDir { get; set; }

        /// <summary>
        /// 歌单地址
        /// </summary>
        public string MusicListPath { get; set; }

        /// <summary>
        /// 信息文件夹
        /// </summary>
        public string InformationsDir { get; set; }

        /// <summary>
        /// 歌词文件夹
        /// </summary>
        public string LyricsDir { get; set; }

        /// <summary>
        /// 乐谱文件夹
        /// </summary>
        public string ScoresDir { get; set; }
        #endregion 以上：/////////////////////非静态变量////////////////////////////

        #region //////////////////////////////静态方法//////////////////////////////

        #endregion 以上：/////////////////////静态方法//////////////////////////////

        #region //////////////////////////////非静态方法////////////////////////////

        /// <summary>
        /// 加载用户设置
        /// </summary>
        public void ConfigLoad()
        {
            //UserConfig_Main.xml
            Dictionary<string, string> ConfigDict = ConverterToDict();
            if (LoadXmlConfig(ConfigPath, "Config", ref ConfigDict))
            { GetValueFromDictionary(ConfigDict); }
        }

        /// <summary>
        /// 用户配置的字典
        /// </summary>
        /// <returns></returns>
        private Dictionary<string, string> ConverterToDict()
        {
            Dictionary<string, string> ConfigDict = new Dictionary<string, string>
            {
                { "CreatorDir", CreatorDir },
            };
            return ConfigDict;
        }

        /// <summary>
        /// 从用户字典中获取变量值
        /// </summary>
        /// <param name="ConfigDict">用户字典</param>
        private void GetValueFromDictionary(Dictionary<string, string> ConfigDict)
        {
            CreatorDir = ConfigDict["CreatorDir"];
        }

        /// <summary>
        /// 加载xml格式的用户字典
        /// </summary>
        /// <param name="strFileName">文件名</param>
        /// <param name="strRoot">根节点</param>
        /// <param name="dict">数据字典</param>
        public bool LoadXmlConfig(string strFileName, string strRoot, ref Dictionary<string, string> dict)
        {
            XmlDocument xmldoc = new XmlDocument();
            XmlReaderSettings settings = new XmlReaderSettings();
            //忽略所有注释
            settings.IgnoreComments = true;
            XmlReader reader = XmlReader.Create(strFileName, settings);
            xmldoc.Load(strFileName);

            XmlNode xmlnode = xmldoc.SelectSingleNode(strRoot);
            XmlNodeList xmlnodelist = xmlnode.ChildNodes;
            XmlNode xmlsubnode;
            foreach (string key in dict.Keys.ToArray())
            {
                xmlsubnode = xmlnode.SelectSingleNode(key);
                if (xmlsubnode != null)
                { dict[key] = xmlsubnode.InnerText; }
            }
            reader.Close();
            return true;
        }

        /// <summary>
        /// 创建指定目录文件夹
        /// </summary>
        /// <param name="path">指定文件夹</param>
        public string CreateFilePath(string path)
        {
            try
            {
                if (!Directory.Exists(path))
                { Directory.CreateDirectory(path); }
            }
            catch (Exception)
            { return null; }

            return path;
        }

        /// <summary>
        /// 拷贝文件夹中的所有内容至另外一个文件夹
        /// 调用此方法需要添加Try Catch
        /// </summary>
        /// <param name="srcPath">源文件夹地址</param>
        /// <param name="desPath">目标文件夹地址</param>
        public void CopyDirectory(string srcPath, string desPath)
        {
            try
            {
                if (!Directory.Exists(srcPath))
                { throw new Exception("源地址未找到文件夹"); }
                if (!Directory.Exists(desPath))
                { Directory.CreateDirectory(desPath); }

                //拷贝当前文件夹下所有文件
                string[] files = Directory.GetFiles(srcPath);
                foreach (string file in files)
                {
                    if (File.Exists(file))
                    {
                        string dirfile = desPath + "\\" + file.Substring(file.LastIndexOf("\\") + 1);
                        FileCopy(file, dirfile);
                    }
                }

                //拷贝当前目录下所有子目录
                string[] subPath = Directory.GetDirectories(srcPath);
                foreach (string dir in subPath)
                {
                    if (Directory.Exists(dir))
                    {
                        string currentdir = desPath + "\\" + dir.Substring(dir.LastIndexOf("\\") + 1);
                        CopyDirectory(dir, currentdir);
                    }

                }
            }
            catch (Exception e)
            { throw e; }
        }

        /// <summary>
        /// 拷贝文件至另外一个路径
        /// </summary>
        /// <param name="srcPath">源文件地址</param>
        /// <param name="desPath">目标文件地址</param>
        public void FileCopy(string srcPath, string desPath)
        {
            // File.Copy(file, dirfile, true);//这个方法会存在文件被占用的情况
            byte[] dat = new byte[1024 * 1024 * 5];
            using (FileStream FsRead = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (FileStream FsWriter = new FileStream(desPath, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    int r = 0;

                    while (true)
                    {
                        r = FsRead.Read(dat, 0, dat.Length);//把读到的数据长度保存起来
                        if (r == 0) //如果读到的数据是0说明已经读完了就跳出方法
                        { break; }
                        FsWriter.Write(dat, 0, r);//把数据写入到新文件中
                    }
                    FsWriter.Close();
                }
                FsRead.Close();
            }
        }

        /// <summary>
        /// 打开目录
        /// </summary>
        /// <param name="folderPath">目录路径（比如：C:\Users\Administrator\）</param>
        public void OpenFolder(string folderPath)
        {
            if (string.IsNullOrEmpty(folderPath)) return;

            Process process = new Process();
            ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe");
            psi.Arguments = folderPath;
            process.StartInfo = psi;

            try
            { process.Start(); }
            catch (Exception ex)
            { throw ex; }
            finally
            { process?.Close(); }
        }

        /// <summary>
        /// 清空指定的文件夹，但不删除文件夹
        /// </summary>
        /// <param name="dir">文件夹路径</param>
        public void DeleteFolder(string dir)
        {
            foreach (string d in Directory.GetFileSystemEntries(dir))
            {
                if (File.Exists(d))
                {
                    FileInfo fi = new FileInfo(d);
                    if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1)
                    { fi.Attributes = FileAttributes.Normal; }
                    File.Delete(d);//直接删除其中的文件    
                }
                else
                {
                    DirectoryInfo d1 = new DirectoryInfo(d);
                    if (d1.GetFiles().Length != 0)
                    { DeleteFolder(d1.FullName); }//递归删除子文件夹  
                    Directory.Delete(d);
                }
            }
        }

        /// <summary>
        /// 检测一个C代码文件中的有效代码行数
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>代码行数</returns>
        public int LinesOfCode(string filename)
        {
            StreamReader sr = File.OpenText(filename);
            string s = sr.ReadToEnd();
            sr.Close();

            bool isLine = false;     //一行中拥有有效字符时为true，该行可记入代码行数
            bool isCommitLf = false; //注释/*...*/中出现至少一个折行时为true
            int lines = 0;             //代码行数统计
            for (int i = 0; i < s.Length; i++)
            {
                //无效字符
                if (s[i] == ' ' || s[i] == '\r' || s[i] == '\t')
                { continue; }

                //搜索到换行，若该行有有效字符
                if (s[i] == '\n')
                {
                    if (isLine)
                    {
                        lines++;
                        isLine = false;
                    }
                    continue;
                }

                //字符串，占多少行按多少行算
                if (s[i] == '\"')
                {
                    while (true)
                    {
                        i++;

                        //如果文件遍历完毕则强行中止
                        if (i >= s.Length)
                        { break; }

                        //再次遇到字符'"'且前方没有或有偶数个'//'时，中止循环并退出
                        if (s[i] == '\"')
                        {
                            int sign = 0, counter = 0;
                            while (true)
                            {
                                sign++;
                                if (i - sign < 0)
                                { break; }
                                else if (s[i - sign] == '\\')
                                { counter++; }
                                else
                                { break; }
                            }
                            if (counter % 2 == 0)
                            { break; }
                        }

                        //字符串中的换行，直接算作一行代码
                        if (s[i] == '\n')
                        {
                            lines++;
                            isLine = true;
                        }
                    }

                    isLine = true;
                    continue;
                }

                //遇到形如 /*...*/ 的注释
                if (s[i] == '/' && i < s.Length - 1)
                {
                    if (s[i + 1] == '*')
                    {
                        i++;
                        while (true)
                        {
                            i++;

                            //如果文件遍历完毕则强行中止
                            if (i >= s.Length)
                            { break; }

                            if (s[i] == '\n')
                            {
                                if (isCommitLf == false)
                                {
                                    if (isLine == true)
                                    {
                                        lines++;
                                        isLine = false;
                                    }
                                    isCommitLf = true;
                                }
                            }
                            if (s[i] == '*' && i < s.Length - 1)
                            {
                                if (s[i + 1] == '/')
                                {
                                    i++;
                                    break;
                                }
                            }
                        }

                        isCommitLf = false;
                        continue;
                    }
                }

                //遇到形如 // 的注释
                if (s[i] == '/' && i < s.Length - 1 && s[i + 1] == '/')
                {
                    if (isLine == true)
                    {
                        lines++;
                        isLine = false;
                    }

                    while (true)
                    {
                        i++;
                        if (i >= s.Length || s[i] == '\n')
                        { break; }
                    }
                    continue;
                }

                //该行有了有效字符，算作一行
                isLine = true;
            }

            //最后一行可能没有字符'\n'结尾
            if (isLine)
            { lines++; }

            return lines;
        }

        /// <summary>
        /// 检测一个文件夹中所有C代码的行数
        /// </summary>
        /// <param name="foldername">文件夹名称</param>
        /// <returns>代码行数</returns>
        public int LinesOfFolder(string foldername)
        {
            //行数统计
            int lines = 0;

            //文件夹信息
            DirectoryInfo dif = new DirectoryInfo(foldername);

            //遍历文件夹中的各子文件夹
            foreach (DirectoryInfo di in dif.GetDirectories())
            { lines += LinesOfFolder(di.FullName); }

            //统计本文件夹中C语言文件代码
            foreach (FileInfo f in dif.GetFiles())
            {
                if (f.Extension == ".cs" || f.Extension == ".cpp" ||
                    f.Extension == ".c" || f.Extension == ".h" ||
                    f.Extension == ".config" || f.Extension == ".resx" ||
                    f.Extension == ".xaml" || f.Extension == ".svg")
                { lines += LinesOfCode(f.FullName); };
            }

            return lines;
        }

        #endregion 以上：/////////////////////非静态方法////////////////////////////
    }
}
